package net.pws.common.persistence.hibernate3;

import javax.sql.DataSource;

import net.pws.common.persistence.DataSourceAware;
import net.pws.common.persistence.QueryStatementManager;
import net.pws.common.persistence.QueryStatementManagerAware;
import net.pws.common.persistence.SessionFactoryAware;
import net.pws.common.persistence.jdbc.JDBCTemplateAware;
import net.pws.common.persistence.jdbc.JdbcTemplateExtension;
import net.pws.common.persistence.jdbc.JdbcTemplateOracleExtension;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.support.DaoSupport;


/**
 */
public class DaoSupportExtension extends DaoSupport implements
                                                   SessionFactoryAware,
                                                   QueryStatementManagerAware,
                                                   DataSourceAware,
                                                   HibernateTemplateAware<HibernateTemplateExtension>,
                                                   JDBCTemplateAware<JdbcTemplateExtension> {
    
    final Log logger = LogFactory.getLog(this.getClass());
    
    protected HibernateTemplateExtension hibernateTemplate;
    
    protected DataSource dataSource;
    
    protected JdbcTemplateExtension jdbcTemplate;
    
    protected QueryStatementManager queryStatementManager;
    
    public QueryStatementManager getQueryStatementManager() {
        return queryStatementManager;
    }
    
    /**
     * @spring.property ref = "queryStatementManager"
     * @param statementManager
     */
    public void setQueryStatementManager(QueryStatementManager queryStatementManager) {
        this.queryStatementManager = queryStatementManager;
    }
    
    protected String getNamedStatement(String statementName) {
        if (logger.isDebugEnabled()) {
            logger.debug("statement name:" + statementName);
        }
        String result = null;
        if (queryStatementManager != null) {
            result = queryStatementManager.getStatementByName(statementName);
            result = (result != null) ? result.trim() : result;
        }
        if (logger.isDebugEnabled()) {
            logger.debug("statement value:" + result);
        }
        return result;
    }
    
    /**
     * Set the Hibernate SessionFactory to be used by this DAO. Will
     * automatically create a HibernateTemplate for the given SessionFactory.
     * 
     * @see #createHibernateTemplate
     * @see #setHibernateTemplate
     * @spring.property ref = "sessionFactory"
     */
    @Autowired
    public final void setSessionFactory(SessionFactory sessionFactory) {
        this.hibernateTemplate = createHibernateTemplate(sessionFactory);
    }
    
    /**
     * Create a HibernateTemplate for the given SessionFactory. Only invoked if
     * populating the DAO with a SessionFactory reference!
     * <p>
     * Can be overridden in subclasses to provide a HibernateTemplate instance with different
     * configuration, or a custom HibernateTemplate subclass.
     * 
     * @param sessionFactory
     *            the Hibernate SessionFactory to create a HibernateTemplate for
     * @return the new HibernateTemplate instance
     * @see #setSessionFactory
     */
    protected HibernateTemplateExtension createHibernateTemplate(SessionFactory sessionFactory) {
        return new HibernateTemplateExtension(sessionFactory);
    }
    
    protected JdbcTemplateOracleExtension createJDBCTemplate(DataSource dataSource) {
        return new JdbcTemplateOracleExtension(dataSource);
    }
    
    /**
     * Return the Hibernate SessionFactory used by this DAO.
     */
    public final SessionFactory getSessionFactory() {
        return (this.hibernateTemplate != null ? this.hibernateTemplate.getSessionFactory()
                                              : null);
    }
    
    /**
     * Set the HibernateTemplate for this DAO explicitly, as an alternative to
     * specifying a SessionFactory.
     * 
     * @see #setSessionFactory
     */
    public final void setHibernateTemplate(HibernateTemplateExtension hibernateTemplate) {
        this.hibernateTemplate = hibernateTemplate;
    }
    
    /**
     * Return the HibernateTemplate for this DAO, pre-initialized with the
     * SessionFactory or set explicitly.
     */
    public final HibernateTemplateExtension getHibernateTemplate() {
        return hibernateTemplate;
    }
    
    public DataSource getDataSource() {
        return dataSource;
    }
    
    @Autowired
    public final void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    
    public void setJdbcTemplate(JdbcTemplateExtension jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public void setJDBCTemplate(JdbcTemplateExtension jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
        
    public JdbcTemplateExtension getJdbcTemplate() {
        return jdbcTemplate;
    }

    protected final void checkDaoConfig() {
        if (this.hibernateTemplate == null) {
            throw new IllegalArgumentException("sessionFactory or hibernateTemplate is required");
        }
    }
    
}
